﻿using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Polly;
using Polly.Timeout;

namespace PollyDemo
{
    public class SimplePollyDemo
    {
        #region FallBack处理
        /// <summary>
        /// 程序FallBack,当时候任务出现异常时，执行FallBack中的内容
        /// </summary>
        public void PollyFallBack()
        {
            Policy myPolly = Policy
                .Handle<ArgumentException>()//只能捕获到ArgumentException的异常
                .Fallback(() =>
                {
                    Console.WriteLine("执行出错");
                }, ex =>
                {
                    Console.WriteLine(ex.Message);
                });

            myPolly.Execute(() =>
            {
                Console.WriteLine("开始执行任务");
                throw new ArgumentException();
                // Console.WriteLine("完成任务");
            });
        }

        /// <summary>
        /// 执行带返回值处理的Polly
        /// </summary>
        /// <returns>The fall back string.</returns>
        public string PollyFallBackString()
        {
            Policy<string> myPolicy = Policy<string>
                .Handle<Exception>()
                .Fallback(() =>
                {
                    Console.WriteLine("执行出错");
                    return "降级的值";
                });

            return myPolicy.Execute(() =>
             {
                 Console.WriteLine("开始执行任务");
                 //return "正常处理";
                 throw new Exception();

             });


        }

        /// <summary>
        /// 指定抓取的异常信息
        /// </summary>
        public void WhereExceptionPolly()
        {
            Policy myPolicy = Policy
                .Handle<Exception>(m => m.Message == "定义错误信息")
                .Fallback(() =>
                {
                    Console.WriteLine("执行的错误信息");
                });

            myPolicy.Execute(() =>
            {
                Console.WriteLine("开始执行处理");
                // throw new Exception("定义错误信息");
                throw new Exception();
            });

        }
        #endregion

        #region Retry重试
        /// <summary>
        /// 重试处理
        /// </summary>
        public void PolicyRetry()
        {
            Policy myPolicy = Policy
                .Handle<Exception>()
                //.RetryForever(); //一直重试
                //.Retry(); //重试一次
                // .Retry(5); //指定重试的次数
                //.WaitAndRetry(5, (value) => { return TimeSpan.FromSeconds(value); });//等待一段时间再执行，一共执行5次
                .WaitAndRetryForever((arg) =>
                {
                    Console.WriteLine(arg); //arg初始值为1，每重试一次自增1.
                    return TimeSpan.FromSeconds(arg);
                }); //等待一段时间再执行，一直执行，直到成功
            int i = 10;
            myPolicy.Execute(() =>
            {
                Console.WriteLine($"开始执行任务{i}");
                if (DateTime.Now.Second % 10 != 0)
                {
                    i++;
                    throw new Exception("Error");
                }
                Console.WriteLine("完成任务");

            });
        }
        #endregion

        #region 熔断处理(CircuitBreaker)
        /// <summary>
        /// 熔断处理
        /// </summary>
        public void CircuitBreaker()
        {
            Policy myPolicy = Policy
                .Handle<Exception>()
                .CircuitBreaker(6, TimeSpan.FromSeconds(5));//连续异常6次之后熔断5秒,在5秒内直接返回异常，5秒后再调用，如果还是异常再熔断5秒。

            while (true)
            {
                try
                {
                    myPolicy.Execute(() =>
                    {
                        Console.WriteLine("开始执行任务");
                        throw new Exception("Error");
                    });
                }
                catch (Exception ex)
                {
                    Console.WriteLine("CircuitBreaker" + ex.Message);
                }
                Thread.Sleep(500);
            }

        }
        #endregion

        #region 策略封闭(PolicyWarp)处理
        /// <summary>
        /// 策略封装处理(Policy不能使用链表的方式进行操作，需要使用Warp将多个Policy组合在一起)，Warp是一种包裹的处理
        /// </summary>
        public void PolicyWarp()
        {
            Policy policyRetry = Policy
                .Handle<Exception>()
                .Retry(3);
            Policy policyFallBack = Policy
                .Handle<Exception>()
                .Fallback(() =>
                {
                    Console.WriteLine("Error处理");
                });
            Policy myPolicy = policyFallBack.Wrap(policyRetry);
            myPolicy.Execute(() =>
            {
                Console.WriteLine("开始执行");
                if (DateTime.Now.Second % 10 != 0)
                {
                    throw new Exception();
                }
                Console.WriteLine("完成任务");
            });


        }
        #endregion

        #region 超时处理(Policy将超时定义为故障)
        /// <summary>
        /// 超时处理(Policy将超时定义为故障)
        /// </summary>
        public void PolicyTimeOut()
        {
            Policy policyTimeOut = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
            Policy policyFallBack = Policy
                .Handle<Exception>()
                .Fallback(() =>
                {
                    Console.WriteLine("超时处理");
                });
            Policy myPolicy = policyFallBack.Wrap(policyTimeOut);
            myPolicy.Execute(() =>
            {
                Console.WriteLine("开始执行处理");
                Thread.Sleep(5000);
                Console.WriteLine("完成处理");
            });

        }
        #endregion

        #region 异步处理
        /// <summary>
        /// 异步处理（无返回值）
        /// </summary>
        /// <returns></returns>
        public async Task PollyTaskAsync()
        {
            Policy policy = Policy
                .Handle<Exception>()
                .FallbackAsync(async c =>
                {
                    await Task.Run(() =>
                    {
                        Console.WriteLine("执行出错");
                    });
                });
            policy = policy.WrapAsync(Policy.TimeoutAsync(3, TimeoutStrategy.Pessimistic, async (context, timespan, task) =>
            {
                await Task.Run(() =>
                {
                    Console.WriteLine("TimeOut");
                });
            }));

            await policy.ExecuteAsync(() =>
            {
                return Task.Run(() =>
                {
                    Console.WriteLine("开始任务");
                    Task.Delay(10000).Wait();
                    Console.WriteLine("结束任务");

                });
            });

        }
        /// <summary>
        /// 异步处理（带有返回值的处理）
        /// </summary>
        /// <returns></returns>
        public async Task<byte[]> PollyAsync()
        {
            Policy<byte[]> myPolicy = Policy<byte[]>
                .Handle<TimeoutRejectedException>()
                .FallbackAsync(async c =>
            {
                return await Task.Run(() =>
                {
                    Console.WriteLine("执行出错");
                    return new byte[0];
                });

            }, async ex =>
                await Task.Run(() =>
                {
                    Console.WriteLine(ex.Exception);
                }));

            myPolicy = myPolicy.WrapAsync(Policy.TimeoutAsync(1, TimeoutStrategy.Pessimistic, async (context, timespan, task) =>
             {
                 await Task.Run(() => { Console.WriteLine("Timeout"); });
             }));

            var bytes = await myPolicy.ExecuteAsync(async () =>
            {
                Console.WriteLine("开始任务");
                HttpClient httpClient = new HttpClient();
                var result = await httpClient.GetByteArrayAsync("http://static.rupeng.com/upload/chatimage/20183/07EB793A4C247A654B31B4D14EC64BCA.png");

                await Task.Delay(TimeSpan.FromSeconds(2));//异步处理中线程等待不是Sleep，而是使用Task.Delay来进行线程的等待。
                Console.WriteLine("完成任务");
                return result;
            });
            return bytes;


        } 
        #endregion
    }
}